package user_service

import (
	"context"
	"errors"
	"git.mycaigou.com/gfyx/common/authorize"
	"git.mycaigou.com/gfyx/common/simplecopier"
	user2 "git.mycaigou.com/gfyx/micro-gfyx-mp-api/http_server/dto/user"
	"git.mycaigou.com/gfyx/micro-gfyx-mp-api/infrastructure/dto/common"
	userNewRepo "git.mycaigou.com/gfyx/micro-gfyx-mp-api/infrastructure/repository/base/user"
	"git.mycaigou.com/gfyx/micro-gfyx-mp-api/infrastructure/repository/tenant"
	"git.mycaigou.com/gfyx/micro-gfyx-mp-api/infrastructure/utils/jwt"
	userBasePb "git.mycaigou.com/gfyx/micro-gfyx-mp-api/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/base"
	userPb "git.mycaigou.com/gfyx/micro-gfyx-mp-api/proto/micro_gfyx_user_service_proto/micro-gfyx-user-service"
	pb "git.mycaigou.com/gfyx/micro-gfyx-mp-api/proto/micro_gfyx_user_service_proto/micro-gfyx-user-service/tenant"
	"git.myscrm.cn/golang/stark/v4"
)

type UserService struct {
	userRepo    UserRepositoryIface
	userNewRepo userNewRepo.UserNewRepositoryIface
	tenantsRepo tenant.TenantsRepositoryIface
}

// NewUserService
// 创建构造函数
func NewUserService(
	userRepo UserRepositoryIface,
	userNewRepo userNewRepo.UserNewRepositoryIface,
	tenantsRepo tenant.TenantsRepositoryIface,
) UserSerivceIface {
	return &UserService{
		userRepo:    userRepo,
		userNewRepo: userNewRepo,
		tenantsRepo: tenantsRepo,
	}
}

// MpBindUser
// 小程序账号绑定
func (s *UserService) MpBindUser(ctx context.Context, openId, mobile string, unionId string) (*LoginInfo, error) {
	loginInfo, err := s.userRepo.MpBindUser(ctx, openId, mobile, unionId)
	if err != nil {
		return nil, err
	}

	if loginInfo == nil {
		return nil, errors.New("登录失败")
	}

	loginInfo.Token, err = s.jwkToken(loginInfo)
	if err != nil {
		return nil, err
	}

	return loginInfo, nil
}

// GetUserInfoByGlobalUserId
// 获取用户信息
func (s *UserService) GetUserInfoByGlobalUserId(ctx context.Context, globalUId string) (*LoginInfo, error) {
	return s.userRepo.GetUserInfo(ctx, &GetUserInfoParams{
		GlobalUId: globalUId,
	})
}

func (s *UserService) TestTenantDbEnable(ctx context.Context, globalUId string) (string, error) {
	return s.userRepo.TestTenantDbEnable(ctx, globalUId)
}

// GetUserInfoByOpenId
// 获取用户信息
func (s *UserService) GetUserInfoByOpenId(ctx context.Context, openId string) (*LoginInfo, error) {
	return s.userRepo.GetUserInfo(ctx, &GetUserInfoParams{OpenId: openId})
}

// MpUserLogin
// 静默登录
func (s *UserService) MpUserLogin(ctx context.Context, openId string, unionId string) (*LoginInfo, error) {
	loginInfo, err := s.userRepo.MpLogin(ctx, openId, unionId)
	if err != nil {
		return nil, err
	}

	if loginInfo == nil {
		return nil, errors.New("登录失败")
	}

	loginInfo.Token, err = s.jwkToken(loginInfo)
	if err != nil {
		return nil, err
	}

	return loginInfo, nil
}

// 短信验证码登录
func (s *UserService) SmsLogin(ctx context.Context, request *common.SmsLoginRequest) (*LoginInfo, error) {
	requestPb := &userPb.LoginByMobileSmsRequest{}
	simplecopier.CopyToStruct(requestPb, request)
	loginInfo, err := s.userRepo.SmsLogin(ctx, requestPb)
	if err != nil {
		return nil, err
	}

	if loginInfo == nil {
		return nil, errors.New("登录失败")
	}

	loginInfo.Token, err = s.jwkToken(loginInfo)
	if err != nil {
		return nil, err
	}

	return loginInfo, nil
}

// jwkToken
// jwk 初始化
func (s *UserService) jwkToken(loginInfo *LoginInfo) (string, error) {
	token := loginInfo.Token
	globalUserId := ""
	tenantCode := ""
	tenantUserId := ""
	tenantUserCode := ""
	tenantUserName := ""
	mobilePhone := ""
	tenantName := ""
	var userId int64
	if loginInfo.UserInfo != nil {
		globalUserId = loginInfo.UserInfo.GlobalUserUid
		tenantUserId = loginInfo.UserInfo.UserId
		tenantUserCode = loginInfo.UserInfo.UserCode
		tenantUserName = loginInfo.UserInfo.UserName
		mobilePhone = loginInfo.UserInfo.Mobile
	}
	if len(loginInfo.TenantList) != 0 {
		tenantCode = loginInfo.TenantList[0].TenantCode
		tenantName = loginInfo.TenantList[0].TenantName
	}
	if tenantCode != "" && tenantUserId != "" {
		//获取新的用户表的自增id
		ctx := context.WithValue(context.Background(), authorize.TENANT_CODE_KEY, tenantCode)
		resp, _ := s.userNewRepo.GetUserIdUserUid(ctx, &userBasePb.GetUserIdUserUidRequest{
			UserUid: tenantUserId,
		})
		if resp != nil {
			userId = resp.Id
		}
	}

	return jwt.DefaultJWT.GenerateToken(token, tenantCode, globalUserId, tenantUserId, tenantUserCode, tenantUserName, mobilePhone, tenantName, userId)
}

// VerifyToken
// 验证token
func (s *UserService) VerifyToken(ctx context.Context, token string) (info *UserInfo, tenantInfo *TenantInfo, err error) {
	return s.userRepo.VerifyToken(ctx, token)
}

// SyncAllUser 全量用户同步
func (s *UserService) SyncAllUser(ctx context.Context, tenantCode string, pagesize int32) (bool, error) {
	if tenantCode == "_all" {
		tenantList, err := s.tenantsRepo.GetTenantAll(ctx, &pb.GetTenantListRequest{})
		if err != nil {
			stark.Logger.Errorf(ctx, "GetTenantAll err:%s", err.Error())
			return false, errors.New("获取租户列表失败")
		}
		syncFailTenantCode := ""
		if len(tenantList.List) > 0 {
			for _, v := range tenantList.List {
				flag, err := s.SyncTenantUser(ctx, v.TenantCode, pagesize)
				if err != nil || flag == false {
					syncFailTenantCode = syncFailTenantCode + v.TenantCode + ", "
					continue
				}
			}
		}

		if syncFailTenantCode != "" {
			return false, errors.New(syncFailTenantCode + "以上租户用户同步失败，失败详情请查看日志信息")
		}
	} else {
		flag, err := s.SyncTenantUser(ctx, tenantCode, pagesize)
		if err != nil || flag == false {
			return false, err
		}
	}

	return true, nil
}

func (s *UserService) SyncAllUserRoleRelation(ctx context.Context, tenantCode string, pagesize int32) (bool, error) {
	if tenantCode == "_all" {
		tenantList, err := s.tenantsRepo.GetTenantAll(ctx, &pb.GetTenantListRequest{})
		if err != nil {
			stark.Logger.Errorf(ctx, "GetTenantAll err:%s", err.Error())
			return false, errors.New("获取租户列表失败")
		}
		syncFailTenantCode := ""
		for _, v := range tenantList.List {
			flag, err := s.SyncUserRoleRelation(ctx, v.TenantCode, pagesize)
			if err != nil || flag == false {
				syncFailTenantCode = syncFailTenantCode + v.TenantCode + ", "
				continue
			}
		}
		if syncFailTenantCode != "" {
			return false, errors.New(syncFailTenantCode + "以上租户用户角色关系同步失败，失败详情请查看日志信息")
		}
	} else {
		flag, err := s.SyncUserRoleRelation(ctx, tenantCode, pagesize)
		if err != nil || flag == false {
			return false, err
		}
	}

	return true, nil
}

// 全量角色同步
func (s *UserService) SyncAllRole(ctx context.Context, tenantCode string, pagesize int32) (bool, error) {
	if tenantCode == "_all" {
		tenantList, err := s.tenantsRepo.GetTenantAll(ctx, &pb.GetTenantListRequest{})
		if err != nil {
			stark.Logger.Errorf(ctx, "GetTenantAll err:%s", err.Error())
			return false, errors.New("获取租户列表失败")
		}
		syncFailTenantCode := ""
		for _, v := range tenantList.List {
			flag, err := s.SyncTenantRole(ctx, v.TenantCode, pagesize)
			if err != nil || flag == false {
				syncFailTenantCode = syncFailTenantCode + v.TenantCode + ", "
				continue
			}
		}
		if syncFailTenantCode != "" {
			return false, errors.New(syncFailTenantCode + "以上租户用户同步失败，失败详情请查看日志信息")
		}
	} else {
		flag, err := s.SyncTenantRole(ctx, tenantCode, pagesize)
		if err != nil || flag == false {
			return false, err
		}
	}

	return true, nil
}

func (s *UserService) SyncAllUserActionRightInfos(ctx context.Context, tenantCode string) (bool, error) {
	if tenantCode == "_all" {
		tenantList, err := s.tenantsRepo.GetTenantAll(ctx, &pb.GetTenantListRequest{})
		if err != nil {
			stark.Logger.Errorf(ctx, "GetTenantAll err:%s", err.Error())
			return false, errors.New("获取租户列表失败")
		}
		syncFailTenantCode := ""
		for _, v := range tenantList.List {
			flag, err := s.SyncUserActionRightInfos(ctx, v.TenantCode)
			if err != nil || flag == false {
				syncFailTenantCode = syncFailTenantCode + v.TenantCode + ", "
				continue
			}
		}
		if syncFailTenantCode != "" {
			return false, errors.New(syncFailTenantCode + "以上租户用户权限同步失败，失败详情请查看日志信息")
		}
	} else {
		flag, err := s.SyncUserActionRightInfos(ctx, tenantCode)
		if err != nil || flag == false {
			return false, err
		}
	}

	return true, nil
}

func (s *UserService) SyncAllOrganizations(ctx context.Context, tenantCode string) (bool, error) {
	if tenantCode == "_all" {
		tenantList, err := s.tenantsRepo.GetTenantAll(ctx, &pb.GetTenantListRequest{})
		if err != nil {
			stark.Logger.Errorf(ctx, "GetTenantAll err:%s", err.Error())
			return false, errors.New("获取租户列表失败")
		}
		syncFailTenantCode := ""
		for _, v := range tenantList.List {
			flag, err := s.SyncOrganizations(ctx, v.TenantCode)
			if err != nil || flag == false {
				syncFailTenantCode = syncFailTenantCode + v.TenantCode + ", "
				continue
			}
		}
		if syncFailTenantCode != "" {
			return false, errors.New(syncFailTenantCode + "以上租户组织同步失败，失败详情请查看日志信息")
		}
	} else {
		flag, err := s.SyncOrganizations(ctx, tenantCode)
		if err != nil || flag == false {
			return false, err
		}
	}

	return true, nil
}

func (s *UserService) SyncTenantUser(ctx context.Context, tenantCode string, pagesize int32) (bool, error) {
	flag, err := s.userRepo.SyncAllUser(ctx, tenantCode, pagesize)
	if err != nil {
		stark.Logger.Error(ctx, "全量同步用户出错，tenant_code:"+tenantCode, "失败信息：", err)
		return false, err
	}
	if flag == false {
		stark.Logger.Error(ctx, "全量同步用户失败，tenant_code:"+tenantCode)
		return false, errors.New("全量同步用户失败，tenant_code:" + tenantCode)
	}
	stark.Logger.Info(ctx, tenantCode+"租户用户全量同步成功")

	return true, nil
}

func (s *UserService) SyncUserRoleRelation(ctx context.Context, tenantCode string, pagesize int32) (bool, error) {
	flag, err := s.userRepo.SyncAllUserRoleRelation(ctx, tenantCode, pagesize)
	if err != nil {
		stark.Logger.Error(ctx, "全量同步用户角色关系出错，tenant_code:"+tenantCode, "失败信息：", err)
		return false, err
	}
	if flag == false {
		stark.Logger.Error(ctx, "全量同步用户角色关系失败，tenant_code:"+tenantCode)
		return false, errors.New("全量同步用户角色关系失败，tenant_code:" + tenantCode)
	}
	stark.Logger.Info(ctx, tenantCode+"租户用户角色关系全量同步成功")

	return true, nil
}

// 同步租户角色
func (s *UserService) SyncTenantRole(ctx context.Context, tenantCode string, pagesize int32) (bool, error) {
	flag, err := s.userRepo.SyncAllRole(ctx, tenantCode, pagesize)
	if err != nil {
		stark.Logger.Error(ctx, "全量角色出错，tenant_code:"+tenantCode, "失败信息：", err)
		return false, err
	}
	if flag == false {
		stark.Logger.Error(ctx, "全量同步角色失败，tenant_code:"+tenantCode)
		return false, errors.New("全量同步角色失败，tenant_code:" + tenantCode)
	}
	stark.Logger.Info(ctx, tenantCode+"租户角色全量同步成功")

	return true, nil
}

func (s *UserService) SyncUserActionRightInfos(ctx context.Context, tenantCode string) (bool, error) {
	flag, err := s.userRepo.SyncAllUserActionRightInfos(ctx, tenantCode)
	if err != nil {
		stark.Logger.Error(ctx, "全量权限出错，tenant_code:"+tenantCode, "失败信息：", err)
		return false, err
	}
	if flag == false {
		stark.Logger.Error(ctx, "全量同步权限失败，tenant_code:"+tenantCode)
		return false, errors.New("全量同步权限失败，tenant_code:" + tenantCode)
	}
	stark.Logger.Info(ctx, tenantCode+"租户用户权限全量同步成功")

	return true, nil
}

func (s *UserService) SyncAllTenantProfit(ctx context.Context, tenantCode string, syncAllTenantProfitRequest *user2.SyncAllTenantProfitRequest) (bool, error) {
	flag, err := s.userRepo.SyncTenantProfit(ctx, tenantCode, syncAllTenantProfitRequest)
	if err != nil {
		stark.Logger.Error(ctx, "租户权益同步出错，tenant_code:"+tenantCode, "失败信息：", err)
		return false, err
	}
	if flag == false {
		stark.Logger.Error(ctx, "租户权益同步flag为false，tenant_code:"+tenantCode)
		return false, errors.New("租户权益同步flag为false，tenant_code:" + tenantCode)
	}
	stark.Logger.Info(ctx, tenantCode+"租户权益同步成功")
	return true, nil
}

func (s *UserService) SyncOrganizations(ctx context.Context, tenantCode string) (bool, error) {
	flag, err := s.userRepo.SyncAllOrganizations(ctx, tenantCode)
	if err != nil {
		stark.Logger.Error(ctx, "全量组织出错，tenant_code:"+tenantCode, "失败信息：", err)
		return false, err
	}
	if flag == false {
		stark.Logger.Error(ctx, "全量同步组织失败，tenant_code:"+tenantCode)
		return false, errors.New("全量同步组织失败，tenant_code:" + tenantCode)
	}
	stark.Logger.Info(ctx, tenantCode+"租户用户组织全量同步成功")

	return true, nil
}

// IncrSyncUser 同步数据给小程序，新的用户表
func (s *UserService) IncrSyncUser(ctx context.Context, tenantCode, operation string, userList []IncrUserInfo) (bool, error) {
	flag, err := s.userRepo.IncrSyncUser(ctx, tenantCode, operation, userList)
	if err != nil {
		stark.Logger.Error(ctx, "增量同步用户出错，tenant_code:"+tenantCode, "失败信息：", err)
		return false, err
	}
	if flag == false {
		stark.Logger.Error(ctx, "增量同步用户失败，tenant_code:"+tenantCode)
		return false, errors.New("增量同步用户失败，tenant_code:" + tenantCode)
	}

	return true, nil
}

// UserApply
// 用户申请信息
func (s *UserService) UserApply(ctx context.Context, mobile string) error {
	return s.userRepo.UserApply(ctx, mobile)
}
